package main;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author admin
 *
 */
public class ResultSet {
	private ArrayList<ItsSet> results;
	private int[] mapping;
	public final static int BY_OVER_PERF = 0;
	public final static int BY_EFFICIENCY = 1;
	private boolean isPolicy = false;
	
	public ResultSet(int[] mapping){
		this.mapping = mapping;
		this.results = new ArrayList<ItsSet>();
	}
	
	public boolean isPolicy() {
		return isPolicy;
	}

	public void setPolicy(boolean isPolicy) {
		this.isPolicy = isPolicy;
	}

	public int[] getSet(int idx){
		if(idx >= 0 && idx < getSize()){
			return results.get(idx).getSet();
		}
		return null;
	}
	
	public ItsSet get(int idx){
		if(idx >= 0 && idx < getSize()){
			return results.get(idx);
		}
		return null;
	}
	
	public Map<String, Double> getPerformance(int idx){
		if(idx >= 0 && idx < getSize()){
			return results.get(idx).getPerformance();
		}
		return null;
	}
	
	public void addItsSet(int[] set, Map<String, Double> performance){
		int[] mappedSet = mapValues(set);
		results.add(new ItsSet(mappedSet, performance));
	}
	
	public void addItsSet(List<Integer> set, Map<String, Double> performance){
		int[] mappedSet = mapValues(set);
		results.add(new ItsSet(mappedSet, performance));
	}
	
	
	private int[] mapValues(int[] input) {
		int output[] = new int[input.length];
		for(int j=0; j<input.length; j++){
			output[j] = mapping[input[j]-1];
		}
		return output;
	}
	
	private int[] mapValues(List<Integer> input) {
		int output[] = new int[input.size()];
		for(int j=0; j<input.size(); j++){
			output[j] = mapping[input.get(j)];
		}
		return output;
	}
	
	/**
	 * by default results sorted by itsSet size (ascending)
	 * 
	 * @param filter
	 */
	public void sort(Map<String, Double> goals, int filter){
		if(filter == BY_EFFICIENCY)
			Collections.sort(results, new ByEfficiency(goals));
		else if(filter == BY_OVER_PERF)
			Collections.sort(results, new ByOverallPerformance());
	}
	
	
	/**
	 * @author admin
	 * 
	 * To correct: should sort by goal problems performance only
	 * Now it takes overall performance for all ITS's problems
	 */
	public class ByEfficiency implements Comparator<ItsSet> {
		private Set<String> goalProblems;
		
		public ByEfficiency(Map<String, Double> goals){
			goalProblems = goals.keySet();
		}
		
		public int compare(ItsSet boy, ItsSet girl) {
			double boyVal = boy.getOverallPerf(goalProblems) / boy.getSize();
			double girlVal = girl.getOverallPerf(goalProblems) / girl.getSize();
			double sdif = boyVal - girlVal;

			if (sdif < 0.0)
				return 1;
			else if (sdif > 0.0)
				return -1;
			return 0;
		}
	}
	
	public class ByOverallPerformance implements Comparator<ItsSet> {
		public int compare(ItsSet boy, ItsSet girl) {
			double boyVal = boy.getOverallPerf();
			double girlVal = girl.getOverallPerf();
			double sdif = boyVal - girlVal;

			if (sdif < 0.0)
				return 1;
			else if (sdif > 0.0)
				return -1;
			return 0;
		}
	}

	
	public int getSize(){
		return results.size();
	}
	
	public String toString(){
		String res= "ResultSet("+ getSize() +"):\n";
		for(ItsSet is : results){
			res += is+"\n";
		}
		return res;
	}
	
	public class ItsSet {
		private int[] set = null;
		private Map<String, Double> performance;
		
		ItsSet(int[] set, Map<String, Double> performance){
			this.set = set;
			this.performance = performance;
		}
		
		public Map<String, Double> getPerformance() {
			return performance;
		}
		
		public int[] getSet(){
			return set;
		}
		
		public double getOverallPerf(){
			double overall = 0.0;
			for(double val : performance.values()){
				overall += val;
			}
			return overall;
		}
		
		public double getOverallPerf(Set<String> goalProblems){
			double overall = 0.0;
			for(String goalProb : goalProblems){
				if(performance.containsKey(goalProb))
					overall += performance.get(goalProb);
			}
			return overall;
		}
		
		public double getPerfFor(String porblem){
			return performance.get(porblem);
		}
		
		public int getSize(){
			return set.length;
		}
		
		public String printSet(){
			String result = "";
			for(int i : getSet()){
				result += i + " ";
			}
			return result;
		}
		
		public String toString(){
			return "Set " + printSet();					
		}
		
		public String printDetails(){
			String res = printSet() +": ";
			for ( Map.Entry<String, Double> goals : performance.entrySet()) {
				String tmp = String.format("%.2f", goals.getValue());
				res += goals.getKey() +"="+ tmp +" ";
			}					
			return res;
		}
		
	}
}
